package org.charles.zhifou.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.charles.zhifou.common.annotation.AuthCheck;
import org.charles.zhifou.common.response.BaseResponse;
import org.charles.zhifou.common.response.ResponseCodeEnum;
import org.charles.zhifou.common.response.ResponseUtils;
import org.charles.zhifou.enums.AppTypeEnum;
import org.charles.zhifou.enums.ScoringStrategyEnum;
import org.charles.zhifou.enums.SqlSortOrderEnum;
import org.charles.zhifou.enums.UserRoleEnum;
import org.charles.zhifou.common.exception.ThrowUtils;
import org.charles.zhifou.model.dto.userAnswer.UserAnswerAddRequest;
import org.charles.zhifou.model.dto.userAnswer.UserAnswerEditRequest;
import org.charles.zhifou.model.dto.userAnswer.UserAnswerQueryRequest;
import org.charles.zhifou.model.dto.userAnswer.UserAnswerUpdateRequest;
import org.charles.zhifou.model.entity.User;
import org.charles.zhifou.model.entity.UserAnswer;
import org.charles.zhifou.model.vo.UserAnswerVO;
import org.charles.zhifou.model.vo.UserVO;
import org.charles.zhifou.service.UserAnswerService;
import org.charles.zhifou.service.UserService;
import org.charles.zhifou.common.utils.SqlUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * <h1>用户答案接口</h1>
 *
 * @author charles
 * @version 1.0
 */
@RestController
@RequestMapping("/userAnswer")
@Slf4j
@Tag(name = "用户答案接口")
public class UserAnswerController {

    @Resource
    private UserAnswerService userAnswerService;

    @Resource
    private UserService userService;

    // region 增删改查

    /**
     * 创建用户答案
     *
     * @param userAnswerAddRequest 用户答案
     * @return 用户答案记录 id
     */
    @PostMapping("/add")
    @Operation(summary = "创建用户答案")
    public BaseResponse<Long> addUserAnswer(@Validated @RequestBody UserAnswerAddRequest userAnswerAddRequest) throws Exception {
        // 封装参数 (App 相关参数需进一步封装)
        UserAnswer userAnswer = new UserAnswer();
        userAnswer.setId(userAnswer.getId());
        userAnswer.setAppId(userAnswerAddRequest.getAppId());
        userAnswer.setAppType(null);
        userAnswer.setScoringStrategy(null);
        userAnswer.setChoices(JSONUtil.toJsonStr(userAnswerAddRequest.getChoices()));
        userAnswer.setResultId(null);
        userAnswer.setResultName(null);
        userAnswer.setResultDesc(null);
        userAnswer.setResultPicture(null);
        userAnswer.setResultScore(null);
        userAnswer.setUserId(userService.getLoginUser().getId());

        // 评分 (顺便添加 App 参数) + 添加到数据库
        userAnswerService.doScore(userAnswer);
        Long newUserAnswerId = userAnswerService.addUserAnswer(userAnswer);

        // 写入数据库
        return ResponseUtils.success(newUserAnswerId);
    }

    /**
     * 删除用户答案
     *
     * @param id 删除答案 id
     * @return 是否成功
     */
    @DeleteMapping("/delete")
    @Operation(summary = "删除用户答案")
    public BaseResponse<Boolean> deleteUserAnswer(
            @Min(value = 1, message = "id 不能小于 1")
            @NotNull(message = "id 不能为空")
            Long id
    ) {
        boolean isSuccessful = userAnswerService.removeUserAnswerById(id);
        return ResponseUtils.success(isSuccessful);
    }

    /**
     * 更新用户答案 (仅管理员)
     *
     * @param userAnswerUpdateRequest 更新用户答案请求
     * @return 是否成功
     */
    @PostMapping("/update")
    @Operation(summary = "更新用户答案")
    @AuthCheck(neededRole = UserRoleEnum.ADMIN)
    public BaseResponse<Boolean> updateUserAnswer(@Validated @RequestBody UserAnswerUpdateRequest userAnswerUpdateRequest) {
        // 封装参数
        UserAnswer userAnswer = new UserAnswer();
        userAnswer.setId(userAnswerUpdateRequest.getId());
        userAnswer.setAppId(userAnswer.getAppId());
        userAnswer.setAppType(null);
        userAnswer.setScoringStrategy(null);
        userAnswer.setChoices(JSONUtil.toJsonStr(userAnswer.getChoices()));
        userAnswer.setResultId(null);
        userAnswer.setResultName(null);
        userAnswer.setResultDesc(null);
        userAnswer.setResultPicture(null);
        userAnswer.setResultScore(null);
        userAnswer.setUserId(null);

        // 操作数据库
        boolean isSuccessful = userAnswerService.updateUserAnswer(userAnswer);
        return ResponseUtils.success(isSuccessful);
    }

    /**
     * 根据 id 获取用户答案 VO
     *
     * @param id 用户答案 id
     * @return 用户答案 VO
     */
    @GetMapping("/get_vo")
    @Operation(summary = "根据 id 获取用户答案 VO")
    public BaseResponse<UserAnswerVO> getUserAnswerVOById(
            @Min(value = 1, message = "id 不能小于 1")
            @NotNull(message = "id 不能为空")
            Long id
    ) {
        // 查询数据库
        UserAnswer userAnswer = userAnswerService.getById(id);
        ThrowUtils.throwIf(userAnswer == null, ResponseCodeEnum.NOT_FOUND_ERROR, "用户答案不存在");

        // 获取封装类, 并补全 UserVO user 属性
        UserAnswerVO userAnswerVO = UserAnswerVO.entityToVo(userAnswer);
        User user = userService.getById(userAnswer.getUserId());
        UserVO userVO = UserVO.entityToVo(user);
        userAnswerVO.setUser(userVO);

        return ResponseUtils.success(userAnswerVO);
    }

    /**
     * 分页获取用户答案列表 (仅管理员)
     *
     * @param userAnswerQueryRequest 查询条件
     * @return 用户答案列表
     */
    @PostMapping("/list/page")
    @Operation(summary = "分页获取用户答案列表")
    @AuthCheck(neededRole = UserRoleEnum.ADMIN)
    public BaseResponse<Page<UserAnswer>> listUserAnswerByPage(@Validated @RequestBody UserAnswerQueryRequest userAnswerQueryRequest) {
        // 分页参数
        long current = userAnswerQueryRequest.getCurrent();
        long size = userAnswerQueryRequest.getPageSize();

        // 查询数据库
        Page<UserAnswer> userAnswerPage = userAnswerService.page(new Page<>(current, size), buildQueryWrapper(userAnswerQueryRequest));
        return ResponseUtils.success(userAnswerPage);
    }

    /**
     * 分页获取用户答案列表 VO
     *
     * @param userAnswerQueryRequest 查询条件
     * @return 用户答案 VO 列表
     */
    @PostMapping("/list/page/vo")
    @Operation(summary = "分页获取用户答案列表 VO")
    public BaseResponse<Page<UserAnswerVO>> listUserAnswerVOByPage(@Validated @RequestBody UserAnswerQueryRequest userAnswerQueryRequest) {
        // 分页参数
        long current = userAnswerQueryRequest.getCurrent();
        long size = userAnswerQueryRequest.getPageSize();

        // 查询数据库并封装返回
        Page<UserAnswer> userAnswerPage = userAnswerService.page(new Page<>(current, size), buildQueryWrapper(userAnswerQueryRequest));
        Page<UserAnswerVO> userAnswerVOPage = new Page<>(current, size, userAnswerPage.getTotal());
        userAnswerVOPage.setRecords(userAnswerPage.getRecords().stream().map(UserAnswerVO::entityToVo).toList());

        return ResponseUtils.success(userAnswerVOPage);
    }

    /**
     * 分页获取当前登录用户创建的用户答案列表
     *
     * @param userAnswerQueryRequest 查询条件
     * @return 用户答案 VO 列表
     */
    @PostMapping("/my/list/page/vo")
    @Operation(summary = "分页获取当前登录用户创建的用户答案列表")
    public BaseResponse<Page<UserAnswerVO>> listMyUserAnswerVOByPage(@Validated @RequestBody UserAnswerQueryRequest userAnswerQueryRequest) {
        // 分页参数
        long current = userAnswerQueryRequest.getCurrent();
        long size = userAnswerQueryRequest.getPageSize();

        // 额外添加 userId 限定
        userAnswerQueryRequest.setUserId(userService.getLoginUser().getId());

        // 查询数据库并封装返回
        Page<UserAnswer> userAnswerPage = userAnswerService.page(new Page<>(current, size), buildQueryWrapper(userAnswerQueryRequest));
        Page<UserAnswerVO> userAnswerVOPage = new Page<>(current, size, userAnswerPage.getTotal());
        userAnswerVOPage.setRecords(userAnswerPage.getRecords().stream().map(UserAnswerVO::entityToVo).toList());

        return ResponseUtils.success(userAnswerVOPage);
    }

    /**
     * 编辑用户答案
     *
     * @param userAnswerEditRequest 用户答案编辑请求
     * @return 是否成功
     */
    @PostMapping("/edit")
    @Operation(summary = "编辑用户答案")
    public BaseResponse<Boolean> editUserAnswer(@Validated @RequestBody UserAnswerEditRequest userAnswerEditRequest) {
        // 封装参数
        UserAnswer userAnswer = new UserAnswer();
        userAnswer.setId(userAnswerEditRequest.getId());
        userAnswer.setAppId(userAnswer.getAppId());
        userAnswer.setAppType(null);
        userAnswer.setScoringStrategy(null);
        userAnswer.setChoices(JSONUtil.toJsonStr(userAnswer.getChoices()));
        userAnswer.setResultId(null);
        userAnswer.setResultName(null);
        userAnswer.setResultDesc(null);
        userAnswer.setResultPicture(null);
        userAnswer.setResultScore(null);
        userAnswer.setUserId(null);

        // 操作数据库
        boolean isSuccessful = userAnswerService.editUserAnswer(userAnswer);
        return ResponseUtils.success(isSuccessful);
    }

    // endregion

    /**
     * 基于雪花算法, 生成用户答案 id, 实现幂等性
     *
     * @return 用户答案 id
     */
    @GetMapping("/generate/id")
    @Operation(summary = "生成用户答案 id")
    public BaseResponse<Long> generateUserAnswerId() {
        return ResponseUtils.success(IdUtil.getSnowflakeNextId());
    }

    public QueryWrapper<UserAnswer> buildQueryWrapper(UserAnswerQueryRequest userAnswerQueryRequest) {
        QueryWrapper<UserAnswer> queryWrapper = new QueryWrapper<>();
        if (userAnswerQueryRequest == null) {
            return queryWrapper;
        }
        // 从对象中取值
        Long id = userAnswerQueryRequest.getId();
        Long appId = userAnswerQueryRequest.getAppId();
        AppTypeEnum appType = userAnswerQueryRequest.getAppType();
        ScoringStrategyEnum scoringStrategy = userAnswerQueryRequest.getScoringStrategy();
        String choices = userAnswerQueryRequest.getChoices();
        Long resultId = userAnswerQueryRequest.getResultId();
        String resultName = userAnswerQueryRequest.getResultName();
        String resultDesc = userAnswerQueryRequest.getResultDesc();
        String resultPicture = userAnswerQueryRequest.getResultPicture();
        Integer resultScore = userAnswerQueryRequest.getResultScore();
        Long userId = userAnswerQueryRequest.getUserId();
        Long notId = userAnswerQueryRequest.getNotId();
        String searchText = userAnswerQueryRequest.getSearchText();
        String sortField = StrUtil.toUnderlineCase(userAnswerQueryRequest.getSortField());
        SqlSortOrderEnum sortOrder = userAnswerQueryRequest.getSortOrder();

        // 补充需要的查询条件
        // 从多字段中搜索
        if (StringUtils.isNotBlank(searchText)) {
            // 需要拼接查询条件
            queryWrapper.and(qw -> qw.like("result_name", searchText).or().like("result_desc", searchText));
        }
        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(choices), "choices", choices);
        queryWrapper.like(StringUtils.isNotBlank(resultName), "result_name", resultName);
        queryWrapper.like(StringUtils.isNotBlank(resultDesc), "result_desc", resultDesc);
        queryWrapper.like(StringUtils.isNotBlank(resultPicture), "result_picture", resultPicture);
        // 精确查询
        queryWrapper.ne(ObjectUtils.isNotEmpty(notId), "id", notId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "user_id", userId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(resultId), "result_id", resultId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(appId), "app_id", appId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(appType), "app_type", appType);
        queryWrapper.eq(ObjectUtils.isNotEmpty(resultScore), "result_score", resultScore);
        queryWrapper.eq(ObjectUtils.isNotEmpty(scoringStrategy), "scoring_strategy", scoringStrategy);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), !SqlSortOrderEnum.DESC.equals(sortOrder), sortField);

        return queryWrapper;
    }
}
